#include "StdAfx.hpp"
#include "Scene.hpp"
#include "KDTree.hpp"
#include "Engine.hpp"


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// class RenderingComponent

RenderingComponent::RenderingComponent()
: Visible(true)
{
}

RenderingComponent::~RenderingComponent()
{
}


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// class LightComponent

LightComponent::LightComponent()
: Enabled(true)
, Color(COLORF_WHITE)
, Range(16.f)
, SpecularEnabled(true)
, ShadowEnabled(false)
, ShadowFactor(0.f)
, ShadowMapDepthBias(-0.002f)
{

}

bool LightComponent::IsVisible()
{
	return Enabled
		&& Range > FLT_EPSILON
		&& (Color.R > FLT_EPSILON || Color.G > FLT_EPSILON || Color.B > FLT_EPSILON);
}


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// class SceneObject

SceneObject::SceneObject()
: m_RenderingComponent(NULL)
, m_LightComponent(NULL)
, m_Scene(NULL)
, m_Parent(NULL)
, m_FirstChild(NULL), m_LastChild(NULL)
, m_PrevSibling(NULL), m_NextSibling(NULL)
, m_PrevXformed(NULL), m_NextXformed(NULL), m_IsOnXformedList(false)
, m_PrevSceneObject(NULL), m_NextSceneObject(NULL)
, m_KDNode(NULL)
, m_Position(VEC3_ZERO)
, m_Orientation(QUATERNION_IDENTITY)
, m_Scaling(VEC3_ONE)
, m_BoundingBox(BOX_ZERO)
, m_TransformDataPresent(true)
, m_LocalToParentTransform(MATRIX_IDENTITY), m_LocalToWorldTransform(MATRIX_IDENTITY)
, m_WorldBoundingBox(BOX_ZERO)
{
}

SceneObject::~SceneObject()
{
	delete m_LightComponent;
	delete m_RenderingComponent;

	for (SceneObjectSiblingIterator it = ChildObjectsBegin(), itNext; it != ChildObjectsEnd(); )
	{
		itNext = it;
		++itNext;

		it->SetParent(GetParent());
		it->Release();

		it = itNext;
	}

	if (m_Scene)
	{
		if (m_Parent)
			m_Parent->RemoveChild(this);
		else
			m_Scene->RemoveTopObject(this);

		m_Scene->UnregisterObject(this);
	}
}

void SceneObject::SetRenderingComponent(RenderingComponent *renderingComponent)
{
	if (renderingComponent == m_RenderingComponent)
		return;
	delete m_RenderingComponent;
	if (renderingComponent)
	{
		assert(renderingComponent->m_SceneObject == NULL);
		renderingComponent->m_SceneObject = this;
	}
	m_RenderingComponent = renderingComponent;
}

void SceneObject::SetLightComponent( LightComponent *component )
{
	if (component == m_LightComponent)
		return;
	delete m_LightComponent;
	if (component)
	{
		assert(component->m_SceneObject == NULL);
		component->m_SceneObject = this;
	}
	m_LightComponent = component;
}

void SceneObject::OnUpdate()
{
	if (m_RenderingComponent)
		m_RenderingComponent->OnUpdate();
	if (m_LightComponent)
		m_LightComponent->OnUpdate();
}

void SceneObject::SetScene(Scene *v)
{
	if (v == m_Scene) return;
	assert(m_Scene == NULL && m_Parent == NULL);

	m_Scene = v;
	m_Scene->RegisterObject(this);
	m_Scene->AddTopObject(this);
}

void SceneObject::SetParent(SceneObject *obj)
{
	if (obj == m_Parent) return;
	assert(m_Scene);

	if (m_Parent)
		m_Parent->RemoveChild(this);
	else
		m_Scene->RemoveTopObject(this);

	m_Parent = obj;

	if (m_Parent)
		m_Parent->AddChild(this);
	else
		m_Scene->AddTopObject(this);

	InvalidateTransformData();
}

SceneObjectSiblingIterator SceneObject::ChildObjectsBegin()
{
	return SceneObjectSiblingIterator(m_FirstChild);
}

SceneObjectSiblingIterator SceneObject::ChildObjectsEnd()
{
	return SceneObjectSiblingIterator(NULL);
}

SceneObjectTreeIterator SceneObject::SubtreeBegin()
{
	return SceneObjectTreeIterator(this, m_FirstChild);
}

SceneObjectTreeIterator SceneObject::SubtreeEnd()
{
	return SceneObjectTreeIterator(this, NULL);
}

void SceneObject::AddChild(SceneObject *obj)
{
	if (m_FirstChild == NULL)
		m_FirstChild = m_LastChild = obj;
	else
	{
		obj->m_PrevSibling = m_LastChild;
		m_LastChild->m_NextSibling = obj;
		m_LastChild = obj;
	}
}

void SceneObject::RemoveChild(SceneObject *obj)
{
	if (obj->m_PrevSibling == NULL)
		m_FirstChild = obj->m_NextSibling;
	else
		obj->m_PrevSibling->m_NextSibling = obj->m_NextSibling;
	
	if (obj->m_NextSibling == NULL)
		m_LastChild = obj->m_PrevSibling;
	else
		obj->m_NextSibling->m_PrevSibling = obj->m_PrevSibling;

	obj->m_PrevSibling = obj->m_NextSibling = NULL;
}

void SceneObject::InvalidateTransformData()
{
	m_TransformDataPresent = false;

	if (GetScene())
		GetScene()->ObjectTransformChange(this);

	for (SceneObjectSiblingIterator it = ChildObjectsBegin(); it != ChildObjectsEnd(); ++it)
		it->InvalidateTransformData();
}

void SceneObject::CalcTransformData()
{
	MATRIX sm, rm;
	Scaling(&sm, m_Scaling);
	QuaternionToRotationMatrix(&rm, m_Orientation);
	
	m_LocalToParentTransform = sm * rm;
	MatrixSetTranslation(&m_LocalToParentTransform, m_Position);

	m_LocalToWorldTransform = m_LocalToParentTransform;
	if (m_Parent)
		m_LocalToWorldTransform *= m_Parent->GetLocalToWorldTransform();

	TransformBox(&m_WorldBoundingBox, m_BoundingBox, m_LocalToWorldTransform);

	m_TransformDataPresent = true;
}

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// class SceneObjectTreeIterator

void SceneObjectTreeIterator::GoToParent()
{
	SceneObject *obj = m_Obj;
	for (;;)
	{
		obj = obj->GetParent();
		
		if (obj == m_Root)
		{
			m_Obj = NULL;
			break;
		}
		if (obj->m_NextSibling)
		{
			m_Obj = obj->m_NextSibling;
			break;
		}
	}
}


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// class Scene

Scene::Scene(common::BOX &WorldBox, const NxSceneDesc &physicsDesc)
: m_WorldBox(WorldBox)
, m_KDTree(new KDTree(WorldBox))
, m_ObjectCount(0)
, m_FirstObject(NULL), m_LastObject(NULL)
, m_FirstTopObject(NULL), m_LastTopObject(NULL)
, m_FirstXformed(NULL), m_LastXformed(NULL)
, m_InsideDestructor(false)
, m_PhysxScene(NULL)
, m_Sky(NULL)
{
	CreatePhysics(physicsDesc);
}

Scene::~Scene()
{
	m_InsideDestructor = true;

	while (m_FirstObject)
		m_FirstObject->Release();

	if (m_Sky)
		m_Sky->Release();

	DestroyPhysics();
}

void Scene::CreatePhysics(const NxSceneDesc &physicsDesc)
{
	assert(g_Engine);

	m_PhysxScene = g_Engine->GetPhysics()->createScene(physicsDesc);
	assert(m_PhysxScene);
}

void Scene::DestroyPhysics()
{
	assert(g_Engine);

	if (m_PhysxScene)
	{
		g_Engine->GetPhysics()->releaseScene(*m_PhysxScene);
		m_PhysxScene = NULL;
	}
}

void Scene::ListAllObjects(SceneObjectPtrVector &out, SceneObjectPredicate *Pred)
{
	out.clear();

	for (SceneObject *obj = m_FirstObject; obj; obj = obj->m_NextSceneObject)
		if (Pred == NULL || Pred->Test(&*obj))
			out.push_back(obj);
}

void Scene::ListObjectsIntersectingFrustum(SceneObjectPtrVector &out, const common::FRUSTUM_PLANES &Frustum, SceneObjectPredicate *Pred)
{
	if (m_KDTree.get())
	{
		m_KDTree->ListObjectsIntersectingFrustum(out, Frustum, Pred);
	}
	else
	{
		// Brute Force Version
		out.clear();

		for (SceneObject *obj = m_FirstObject; obj; obj = obj->m_NextSceneObject)
			if (Pred == NULL || Pred->Test(&*obj))
				if (BoxToFrustum_Fast(obj->GetWorldBoundingBox(), Frustum))
					out.push_back(obj);
	}
}

void Scene::ListObjectsIntersectingSweptBox(SceneObjectPtrVector &out, const common::BOX &box, const common::VEC3 &boxDir, SceneObjectPredicate *Pred)
{
	if (m_KDTree.get())
	{
		m_KDTree->ListObjectsIntersectingSweptBox(out, box, boxDir, Pred);
	}
	else
	{
		// Brute Force Version
		out.clear();

		float t1, t2;
		for (SceneObject *obj = m_FirstObject; obj; obj = obj->m_NextSceneObject)
			if (Pred == NULL || Pred->Test(&*obj))
				if (SweptBoxToBox(box, obj->GetWorldBoundingBox(), boxDir, &t1, &t2) && t1 >= 0.f)
					out.push_back(obj);
	}
}

/*void Scene::ListObjectsIntersectingBox(SceneObjectPtrVector &out, const common::BOX &Box, SceneObjectPredicate *Pred)
{
	out.clear();

	for (SceneObject *obj = m_FirstObject; obj; obj = obj->m_NextSceneObject)
		if (Pred == NULL || Pred->Test(&*obj))
			if (BoxToBox(obj->GetWorldBoundingBox(), Box))
				out.push_back(obj);
}*/

void Scene::ListObjectsIntersectingSphere(SceneObjectPtrVector &out, const common::VEC3 &sphereCenter, float sphereRadius, SceneObjectPredicate *pred)
{
	out.clear();

	if (m_KDTree.get())
		m_KDTree->ListObjectsIntersectingSphere(out, sphereCenter, sphereRadius, pred);
	else
	{
		// Brute Force Version
		out.clear();
		for (SceneObject *obj = m_FirstObject; obj; obj = obj->m_NextSceneObject)
			if (pred == NULL || pred->Test(&*obj))
				if (SphereToBox(sphereCenter, sphereRadius, obj->GetWorldBoundingBox()))
					out.push_back(obj);
	}
}

void Scene::RegisterObject(SceneObject *obj)
{
	assert(obj->m_PrevSceneObject == NULL && obj->m_NextSceneObject == NULL);

	if (m_FirstObject == NULL)
		m_FirstObject = m_LastObject = obj;
	else
	{
		obj->m_PrevSceneObject = m_LastObject;
		m_LastObject->m_NextSceneObject = obj;
		m_LastObject = obj;
	}

	if (m_KDTree != NULL)
		m_KDTree->InsertObject(obj);

	m_ObjectCount++;
}

void Scene::UnregisterObject(SceneObject *obj)
{
	m_ObjectCount--;

	if (obj->m_IsOnXformedList)
	{
		if (obj->m_PrevXformed == NULL)
			m_FirstXformed = obj->m_NextXformed;
		else
			obj->m_PrevXformed->m_NextXformed = obj->m_NextXformed;
		
		if (obj->m_NextXformed == NULL)
			m_LastXformed = obj->m_PrevXformed;
		else
			obj->m_NextXformed->m_PrevXformed = obj->m_PrevXformed;
		
		obj->m_IsOnXformedList = false;
	}

	if (m_KDTree != NULL && !m_InsideDestructor)
		m_KDTree->RemoveObject(obj);

	if (obj->m_PrevSceneObject == NULL)
		m_FirstObject = obj->m_NextSceneObject;
	else
		obj->m_PrevSceneObject->m_NextSceneObject = obj->m_NextSceneObject;
	
	if (obj->m_NextSceneObject == NULL)
		m_LastObject = obj->m_PrevSceneObject;
	else
		obj->m_NextSceneObject->m_PrevSceneObject = obj->m_PrevSceneObject;

	obj->m_PrevSceneObject = obj->m_NextSceneObject = NULL;
}

void Scene::AddTopObject(SceneObject *obj)
{
	assert(obj->m_PrevSibling == NULL && obj->m_NextSibling == NULL);

	if (m_FirstTopObject == NULL)
		m_FirstTopObject = m_LastTopObject = obj;
	else
	{
		obj->m_PrevSibling = m_LastTopObject;
		m_LastTopObject->m_NextSibling = obj;
		m_LastTopObject = obj;
	}
}

void Scene::RemoveTopObject(SceneObject *obj)
{
	if (obj->m_PrevSibling == NULL)
		m_FirstTopObject = obj->m_NextSibling;
	else
		obj->m_PrevSibling->m_NextSibling = obj->m_NextSibling;
	
	if (obj->m_NextSibling == NULL)
		m_LastTopObject = obj->m_PrevSibling;
	else
		obj->m_NextSibling->m_PrevSibling = obj->m_PrevSibling;

	obj->m_PrevSibling = obj->m_NextSibling = NULL;
}

void Scene::ObjectTransformChange(SceneObject *obj)
{
	if (m_KDTree == NULL) return;

	// Immediate
	{
		m_KDTree->ObjectTransformChange(obj);
	}

	// Deferred
	{
		if (obj->m_IsOnXformedList) return;

		assert(obj->m_PrevXformed == NULL && obj->m_NextXformed == NULL);

		if (m_FirstXformed == NULL)
			m_FirstXformed = m_LastXformed = obj;
		else
		{
			obj->m_PrevXformed = m_LastXformed;
			m_LastXformed->m_NextXformed = obj;
			m_LastXformed = obj;
		}

		obj->m_IsOnXformedList = true;
	}
}

void Scene::ApplyDeferredObjectTransforms()
{
	SceneObject *currObj = m_FirstXformed, *nextObj;
	while (currObj)
	{
		nextObj = currObj->m_NextXformed;

		currObj->m_PrevXformed = currObj->m_NextXformed = NULL;
		currObj->m_IsOnXformedList = false;

		m_KDTree->ObjectTransformChange(currObj);

		currObj = nextObj;
	}

	m_FirstXformed = m_LastXformed = NULL;
}

void Scene::SetSky( ISky *sky )
{
	UpdateObjPtr<ISky>(m_Sky, sky);
}
